今天我們來為我們昨天做的「Click! Serve!」增加一些「設定」。
昨天我們用最簡單的設定讓 pkg 可以將程式打包成可執行檔,今天我們讓它不要亂放產生出來的檔案,以及讓產生出來的檔案不要叫「index.exe」。
我們更新我們的 package.json 檔:
{
"name": "serv",
"version": "1.0.0",
"description": "",
"main": "index.js",
"bin": {
"serv": "index.js"
},
"scripts": {
"build": "pkg ."
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"koa": "^2.13.3",
"koa-static": "^5.0.0"
},
"devDependencies": {
"pkg": "^5.3.3"
},
"pkg": {
"outputPath": "dist"
}
}
增加了一個 bin
的項目,告訴 pkg 我們的 entry 是 index.js。
然後把 script
中的 pkg index.js
改成 pkg .
代表讀這個專案資料夾的 package.json 的設定。
最後加上 pkg
讓 pkg 把產生的檔案輸出至 dist
資料夾。
因為多了一些功能,所以將程式分檔案放到 src 資料夾中。
然後把 index.js 改成:
require("./src/main");
main.js 是主程式,它把處裡參數的工作跟伺服器分開給兩個檔案,看起來很簡單。
const config = require("./config");
const createServer = require("./server");
createServer(config);
流程看起來好舒服,不用管到底怎麼抓參數或建立伺服器的。
這個檔案用來處理參數,並將處裡好的參數 exports 出去。
const process = require("process");
const path = require("path");
// 預設參數,如果用戶沒設定,就用它
const defaultConfig = {
port: 80,
folder: "www",
log: false,
logFile: "log.txt",
};
// 抓參數,第一個是 Node.js 位置,第二個是 js 檔位置,雖然打包但不變
const argv = process.argv.slice(2);
const config = extractConfig(argv);
// 如果使用者想要 help 的話,給簡單的 help
if (config["help"] || config["h"] || config["?"] || config["-help"] || config["-h"] || config["-?"] || config["--help"] || config["--h"] || config["--?"]) {
console.log("Usage: serv [port=80] [folder=www] [log] [logFile=log.txt]");
process.exit(0);
}
// 參數本來應為 key=val 或 key,這裡把他們拆開
function extractConfig(argv) {
let config = {};
for (let i = 0; i < argv.length; i++) {
let arg = argv[i];
arg = arg.split("=");
const key = arg.shift();
let value = arg.join("=") || true;
if (value[0] === '"' && value[value.length - 1] === '"') value = value.substring(1, value.length - 1);
config[key] = value;
}
return check(config);
}
// 處裡一些轉型問題或相對絕對路徑的轉換
function check(config) {
if (config.port) config.port = parseInt(config.port);
if (config.log) config.log = config.log !== "false" && config.log !== "0";
if (config.folder) config.folder = path.isAbsolute(config.folder) ? config.folder : path.join(process.cwd(), config.folder);
if (config.logFile) config.logFile = path.isAbsolute(config.logFile) ? config.logFile : path.join(process.cwd(), config.logFile);
return config;
}
// 合併預設與自訂參數後匯出
module.exports = Object.assign({}, defaultConfig, config);
參數的抓取、合併以及型別路徑轉換等都在此完成。
這個檔案會 exports 一個建立 server 用的函式,然後由 main.js 把處裡好的參數丟進去用。
const fs = require("fs");
const Koa = require("koa");
function createServer({ port, folder, log, logFile }) {
const app = new Koa();
// 因為 log 會一直寫入,所以用 stream
let logFileStream;
if (log) logFileStream = fs.createWriteStream(logFile, { flags: "a" });
app.use(async (ctx, next) => {
console.log(`Process ${ctx.request.method} ${ctx.request.url} from ${ctx.request.ip}`);
if (log) logFileStream.write(`${new Date().toISOString()} ${ctx.request.method} ${ctx.request.url} from ${ctx.request.ip}\n`);
await next();
});
app.use(require("koa-static")(folder));
app.listen(port);
console.log(`Server started at port ${port}`);
console.log(`Serving static files from ${folder}`);
console.log(`Visit http://localhost:${port}/ to see your website.`);
if (log) console.log(`Log file: ${logFile}`);
if (log) logFileStream.write(`=====\n${new Date().toISOString()} Server Started.\n`);
if (log) logFileStream.write(`${new Date().toISOString()} Serving static files from ${folder}\n`);
}
module.exports = createServer;
基本上這個部分跟昨天的程式相似度非常高,只是多了些 log 的部分而已。
來實測程式吧!
help 指令 OK!
不輸入任何參數執行也 OK!(當然你可以 Click 點開)
帶入參數執行也都 OK!!
同時在不同 port 執行兩個 server 也 OK!
而且,log 有正常運作:
基本上都 OK 啦!(不會寫測試)
讚讚!寫出一個應該可以有用的程式了。
再來我們看看能不能用 Electron 給他個 GUI 吧!
以 10/08 20:00 ~ 10/09 20:00 文章觀看數增加值排名
+190
[訪談] APCS x 競程選手 Colten
+133
LeetCode 雙刀流:62. Unique Paths
+117
【Day24】維持權限 — 隱藏後門(一)
+116
Day27 vue.js簡易照片上傳功能(base64)
+114
Angular 深入淺出三十天:表單與測試 Day24 - Reactive Forms 進階技巧 - Auto-Complete Searching
+110
【在 iOS 開發路上的大小事-Day27】透過 Firebase 來管理資料 (Cloud Firestore 篇) Part1
+108
Day 24 快速啟動個 JSON Server
+108
Day24-按鈕分身術(下)_我的分身想去哪
+108
Day24 read-write lock
+106
Day24 Let's ODOO: Discuss
恭喜 Sky Hong 同學封頂!!
今天訪談說好久喔,差點來不及寫了 XD